package com.xt.xxb;

import com.xt.xxb.taobao.TbApi;
import com.xt.xxb.task.HeartbeatRunnable;
import com.xt.xxb.task.OrderRunnable;
import org.apache.commons.lang3.RandomUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;

import javax.swing.*;
import java.awt.*;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 自定义浏览器插件
 */
public class Main {
    private final static String LOGIN_PAGE = "https://trade.taobao.com/trade/itemlist/list_sold_items.htm";
    public final static String RANDOM_KEY = "e51ebbd0a087400a8dc9845f43af3f13";
    private static WebDriver driver = null;
    private static JTextArea jTextAreaLogger = null;
    private static JTextField jTextFieldUser = null;
    private static JPasswordField jPasswordFieldPass = null;
    private static JTextField jTextFieldGateway = null;
    private static JTextField jTextFieldSysUser = null;
    private static JPasswordField jPasswordFieldSysPass = null;
    private static JScrollBar jScrollBar = null;
    private static SysInfo sysInfo = null;
    private static JButton submitButton = null;

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("TB店铺监控");
        frame.setLayout(new BorderLayout());
        frame.setSize(1024, 480);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        frame.setResizable(false);
        JPanel inputPanel = new JPanel(new BorderLayout());
        JPanel btnPanel = new JPanel();
        jTextFieldGateway = new JTextField();
        jTextFieldGateway.setEditable(true);
        jTextFieldGateway.setPreferredSize(new Dimension(80, 28));
        jTextFieldSysUser = new JTextField();
        jTextFieldSysUser.setEditable(true);
        jTextFieldSysUser.setPreferredSize(new Dimension(80, 28));
        jPasswordFieldSysPass = new JPasswordField();
        jPasswordFieldSysPass.setEditable(true);
        jPasswordFieldSysPass.setPreferredSize(new Dimension(80, 28));
        jTextFieldUser = new JTextField();
        jTextFieldUser.setEditable(true);
        jTextFieldUser.setPreferredSize(new Dimension(80, 28));
        jPasswordFieldPass = new JPasswordField();
        jPasswordFieldPass.setEditable(true);
        jPasswordFieldPass.setPreferredSize(new Dimension(80, 28));
        Box textBox = Box.createVerticalBox();
        Box box1 = Box.createHorizontalBox();
        box1.add(Box.createHorizontalStrut(10));
        box1.add(new JLabel("  后台网关:  "));
        box1.add(Box.createHorizontalStrut(10));
        box1.add(jTextFieldGateway);
        box1.add(Box.createHorizontalStrut(10));

        Box box3 = Box.createHorizontalBox();
        box3.add(Box.createHorizontalStrut(10));
        box3.add(new JLabel("  码商账号:  "));
        box3.add(Box.createHorizontalStrut(10));
        box3.add(jTextFieldSysUser);
        box3.add(Box.createHorizontalStrut(10));

        Box box4 = Box.createHorizontalBox();
        box4.add(Box.createHorizontalStrut(10));
        box4.add(new JLabel("  码商密码:  "));
        box4.add(Box.createHorizontalStrut(10));
        box4.add(jPasswordFieldSysPass);
        box4.add(Box.createHorizontalStrut(10));

        Box box5 = Box.createHorizontalBox();
        box5.add(Box.createHorizontalStrut(10));
        box5.add(new JLabel("  淘宝账号:  "));
        box5.add(Box.createHorizontalStrut(10));
        box5.add(jTextFieldUser);
        box5.add(Box.createHorizontalStrut(10));
        Box box6 = Box.createHorizontalBox();
        box6.add(Box.createHorizontalStrut(10));
        box6.add(new JLabel("  淘宝密码:  "));
        box6.add(Box.createHorizontalStrut(10));
        box6.add(jPasswordFieldPass);
        box6.add(Box.createHorizontalStrut(10));

        textBox.add(box1);
        textBox.add(box3);
        textBox.add(box4);
        textBox.add(box5);
        textBox.add(box6);
        inputPanel.add(textBox, BorderLayout.NORTH);
        submitButton = new JButton("提交");
        btnPanel.add(submitButton, BorderLayout.SOUTH);

        jTextAreaLogger = new JTextArea();
        jTextAreaLogger.setLineWrap(true);
        jTextAreaLogger.setEditable(false);
        JScrollPane jScrollPane = new JScrollPane(jTextAreaLogger);
        jScrollBar = jScrollPane.getVerticalScrollBar();
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                if (JOptionPane.showConfirmDialog(null, "浏览器关闭后将停止店铺监控，确定要关闭吗？", "提示", JOptionPane.YES_NO_OPTION,
                        JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
                    System.exit(0);
                }
            }
        });
        frame.add(inputPanel, BorderLayout.NORTH);
        frame.add(jScrollPane, BorderLayout.CENTER);
        frame.add(btnPanel, BorderLayout.SOUTH);
        frame.setVisible(true);
        Main.logger("已经准备就绪，等待提交指令");
        submitButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                submit();
            }

        });
    }

    private static void submit() {
        String gateway = jTextFieldGateway.getText();
        if (gateway == null || gateway.isEmpty()) {
            JOptionPane.showMessageDialog(null, "后台网关不能为空", "提示", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String sysUser = jTextFieldSysUser.getText();
        if (sysUser == null || sysUser.isEmpty()) {
            JOptionPane.showMessageDialog(null, "码商账号不能为空", "提示", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String sysPass = new String(jPasswordFieldSysPass.getPassword());
        if (sysPass.isEmpty()) {
            JOptionPane.showMessageDialog(null, "码商密码不能为空", "提示", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String username = jTextFieldUser.getText();
        if (username == null || username.isEmpty()) {
            JOptionPane.showMessageDialog(null, "店铺账号不能为空", "提示", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String pass = new String(jPasswordFieldPass.getPassword());
        if (pass.isEmpty()) {
            JOptionPane.showMessageDialog(null, "店铺密码不能为空", "提示", JOptionPane.ERROR_MESSAGE);
            return;
        }
        sysInfo = new SysInfo(gateway, sysUser, sysPass, username, pass);
        try {
            login(username, pass);
        } catch (Exception ignore) {
            if (driver != null) {
                driver.quit();
            }
            Main.logger("登录失败");
        }
    }

    /**
     * 自动登录
     *
     * @param username
     * @param password
     */
    private static void login(String username, String password) {
        loadChromeDriver();
        try {
            Thread.sleep(RandomUtils.nextInt(3000, 5000));
        } catch (InterruptedException ignore) {
        }
        if (driver == null) {
            Main.logger("浏览器加载失败");
            return;
        }
        WebElement userMobile = driver.findElement(By.id("fm-login-id"));
        userMobile.sendKeys(username);
        try {
            Thread.sleep(RandomUtils.nextInt(1000, 3000));
        } catch (InterruptedException ignore) {
        }
        WebElement passwordButton = driver.findElement(By.id("fm-login-password"));
        passwordButton.sendKeys(password);
        try {
            Thread.sleep(RandomUtils.nextInt(1000, 3000));
        } catch (InterruptedException ignore) {
        }
        boolean verify = verify(driver);
        if (!verify) {
            Main.logger("登录失败，滑块验证失败");
            driver.quit();
        }
        try {
            Thread.sleep(RandomUtils.nextInt(1000, 3000));
        } catch (InterruptedException ignore) {
        }
        WebElement submitButton = driver.findElement(By.id("login-form")).findElement(By.tagName("button"));
        submitButton.click();
    }

    /**
     * 初始化浏览器，http://httpbin.org/get 检测代理是否生效
     */
    private static void loadChromeDriver() {
        String sysPath = System.getProperty("user.dir");
        System.setProperty("webdriver.chrome.driver", sysPath + "\\chromedriver.exe");
        ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.setExperimentalOption("excludeSwitches", new Object[]{"enable-automation"});
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().maximize();
        driver.get(LOGIN_PAGE);

        OrderRunnable orderRunnable = new OrderRunnable();
        ScheduledExecutorService orderExecutorService = new ScheduledThreadPoolExecutor(5,
                new org.apache.commons.lang3.concurrent.BasicThreadFactory.Builder().namingPattern("order-schedule-pool-%d").daemon(true).build());
        orderExecutorService.scheduleAtFixedRate(orderRunnable, 60, 5, TimeUnit.SECONDS);

        HeartbeatRunnable heartbeatRunnable = new HeartbeatRunnable();
        ScheduledExecutorService heartbeatExecutorService = new ScheduledThreadPoolExecutor(5, new org.apache.commons.lang3.concurrent.BasicThreadFactory.Builder().namingPattern("heartbeat-schedule-pool-%d").daemon(true).build());
        heartbeatExecutorService.scheduleAtFixedRate(heartbeatRunnable, 1, 5, TimeUnit.MINUTES);
    }

    /**
     * 获取cookie
     *
     * @return
     */
    public static String getCookiesStr() {
        StringBuilder result = new StringBuilder();
        Set<Cookie> set = driver.manage().getCookies();
        for (Cookie cookie : set) {
            result.append(cookie.getName().trim()).append("=").append(cookie.getValue()).append(";");
        }
        return result.toString();
    }

    public static void logger(String text) {
        if (jTextAreaLogger == null) {
            return;
        }
        String today = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        jTextAreaLogger.append("      " + today + " " + text);
        jTextAreaLogger.append("\r\n");
        try {
            Thread.sleep(10);
        } catch (InterruptedException ignore) {
        }
        jScrollBar.setValue(jScrollBar.getMaximum());
    }

    /**
     * 判断是否登录
     *
     * @return
     */
    public static boolean isLogin() {
        String cookie = getCookiesStr();
        if (cookie == null || cookie.isEmpty()) {
            Main.logger("无效cookie,请确认是否登录");
            return false;
        }
        if (!cookie.contains("_tb_token_")) {
            Main.logger("无效cookie,请确认是否登录");
            return false;
        }
        if (!cookie.contains("_nk_") && !cookie.contains("tracknick")) {
            Main.logger("无效cookie,请确认是否登录");
            return false;
        }
        if (!cookie.contains("_l_g_") && !cookie.contains("lgc")) {
            Main.logger("无效cookie,请确认是否登录");
            return false;
        }
        return true;
    }

    /**
     * 滑块验证，尝试三次
     *
     * @param driver
     * @return
     */
    public static boolean verify(WebDriver driver) {
        WebElement noCaptchaPassword = driver.findElement(By.id("nocaptcha-password"));
        boolean displayed = noCaptchaPassword.isDisplayed();
        if (!displayed) {
            return true;
        }
        if (verifyNoCaptcha(driver)) {
            return true;
        }
        ((JavascriptExecutor) driver).executeScript("noCaptcha.reset(1);");
        try {
            Thread.sleep(300);
        } catch (InterruptedException ignore) {
        }
        if (verifyNoCaptcha(driver)) {
            return true;
        }
        try {
            Thread.sleep(300);
        } catch (InterruptedException ignore) {
        }
        ((JavascriptExecutor) driver).executeScript("noCaptcha.reset(1);");
        try {
            Thread.sleep(300);
        } catch (InterruptedException ignore) {
        }
        return verifyNoCaptcha(driver);
    }

    public static boolean verifyNoCaptcha(WebDriver driver) {
        try {
            WebElement source = driver.findElement(By.id("nc_1_n1z"));
            Actions actions = new Actions(driver);
            // 按住左键不放
            actions.clickAndHold(source).perform();
            try {
                Thread.sleep(200);
            } catch (InterruptedException ignore) {
            }
            // 开始滑动
            int distance = 258; // 滑动距离
            List<MoveEntity> list = getMoveEntity(distance);
            actions.clickAndHold(source).perform();
            for (MoveEntity moveEntity : list) {
                actions.moveByOffset(moveEntity.getX(), moveEntity.getY()).perform();
                try {
                    Thread.sleep(moveEntity.getSleepTime());
                } catch (InterruptedException ignore) {
                }
            }
            actions.release(source).perform();
            return driver.findElements(By.id("nc_1_n1z")).size() > 0 && source.getAttribute("class").contains("btn_ok");
        } catch (Exception ignore) {
        }
        return false;
    }

    /**
     * 路径
     *
     * @param distance
     */
    public static List<MoveEntity> getMoveEntity(int distance) {
        List<MoveEntity> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < distance; ) {
            MoveEntity moveEntity = new MoveEntity();
            int d = 1 + random.nextInt(20);
            i += d;
            if (i > distance) {
                i -= d;
                d = distance - i;
                i += d;
            }
            moveEntity.setX(d);
            moveEntity.setY(0);
            moveEntity.setSleepTime(0);
            list.add(moveEntity);
        }
        return list;
    }

    public static SysInfo getSysInfo() {
        return sysInfo;
    }

    public static void heartbeat() {
        boolean isNeedLoad = TbApi.isNeedRelogin(getCookiesStr());
        if (isNeedLoad) {
            if (driver != null) {
                driver.quit();
            }
            submit();
        }
    }

    /**
     * 清空文本框
     */
    public static void clear() {
        if (jTextAreaLogger == null) {
            return;
        }
        jTextAreaLogger.setText("");
    }
}
